package main

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"github.com/mr-tron/base58"
	"io"
	"net/http"
	"strings"
)

func GetBlock(block int64) string {

	url := "https://mainnet.helius-rpc.com/?api-key=a4b0ed9e-8646-4918-8b5c-4f5dade06e4b"

	jsonStr := fmt.Sprintf(`{
		"jsonrpc": "2.0",
		"id": "1",
		"method": "getBlock",
		"params": [%d,{"maxSupportedTransactionVersion": 0}]
	}`, block)

	jsonData := strings.NewReader(jsonStr)

	request, err := http.NewRequest("POST", url, jsonData)

	if err != nil {
		fmt.Printf("Error create Request：%v", err)
	}

	request.Header.Add("Content-Type", "application/json")

	res, err := http.DefaultClient.Do(request)

	if err != nil {
		fmt.Printf("Error create Client：%v", err)
	}

	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)

	if err != nil {
		fmt.Printf("Error create Client：%v", err)
	}

	//fmt.Println(res)
	//fmt.Println(string(body))

	return string(body)
}

const pumpfunProgramId = "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA"

var (
	BuyDiscriminator  = []byte{102, 6, 61, 18, 1, 218, 235, 234}
	SellDiscriminator = []byte{51, 230, 133, 164, 1, 127, 131, 173}
)

func main() {

	result := GetBlock(378067747)

	var dataMap map[string]interface{}

	err := json.Unmarshal([]byte(result), &dataMap)
	if err != nil {
		fmt.Sprintf("转换错误%v", err)
	}

	resultMap := dataMap["result"].(map[string]interface{})

	transactions := resultMap["transactions"].([]interface{})

	for _, trans := range transactions {
		//fmt.Printf("transaction:%v", trans)
		transaction := trans.(map[string]interface{})["transaction"].(map[string]interface{})

		msgMap := transaction["message"].(map[string]interface{})
		accountKeys := msgMap["accountKeys"].([]interface{})
		instructions := msgMap["instructions"].([]interface{})

		for _, instruction := range instructions {
			instructionMap := instruction.(map[string]interface{})
			programId := accountKeys[int64(instructionMap["programIdIndex"].(float64))]
			if programId == pumpfunProgramId {
				dataBase58 := instructionMap["data"].(string)
				dataBytes, err := base58.Decode(dataBase58)
				if err != nil {
					fmt.Printf("Error decoding base58: %v\n", err)
					return
				}
				if len(dataBytes) >= 8 {
					currentData := dataBytes[:8]
					if bytes.Equal(currentData, BuyDiscriminator) {
						fmt.Println("Operation:", "swap")
						fmt.Println("Direction:", "Buy(SOL -> Token)")

						if len(dataBytes) >= 24 {
							baseAmountOut := binary.LittleEndian.Uint64(dataBytes[8:16])
							maxQuoteAmountIn := binary.LittleEndian.Uint64(dataBytes[16:24])

							fmt.Printf(" Buy parameter: \n")
							fmt.Printf(" Base Amount out: %d (tokens received)\n", baseAmountOut)
							fmt.Printf(" Max quote in: %d (max Sol to spend)\n", maxQuoteAmountIn)

							fmt.Println("-----------------------------------")
						}
					} else if bytes.Equal(currentData, SellDiscriminator) {
						fmt.Println("Operation:", "swap")
						fmt.Println("Direction:", "Sell(Token -> SOL)")

						if len(dataBytes) >= 24 {
							baseAmountOut := binary.LittleEndian.Uint64(dataBytes[8:16])
							maxQuoteAmountIn := binary.LittleEndian.Uint64(dataBytes[16:24])

							fmt.Printf(" Seller parameter: \n")
							fmt.Printf(" Base Amount In: %d (tokens to sell)\n", baseAmountOut)
							fmt.Printf(" Min quote out: %d (min Sol to received)\n", maxQuoteAmountIn)
						}

						fmt.Println("-----------------------------------")
					}
				}
			}
		}
	}
}
